/* Team Directories
 *
 * You are free to do whatever you want with this code. Frankly we don't give a damn.
 * 
 *  
 * Copyright GNU General Public License v3
 */

package StudyBuddy;
import java.io.*;
import java.net.*;
import javax.swing.*;

/**
 *
 * @author Gabriel
 */


public class Plugin{

private Object newclass; // newclass
private Runnable plugin; // plugin pointer
private String name; //The name of the Plugin
private File pluginlocation; // The Location of the plugin in the file system
public boolean loaded = false; // This will tell if the plugin is loaded. This is a public variable.

    public Plugin(File newfile){
        /** The Plugin constructor merely saves the locaiton of the plugin into memory
         * this is done to conserve memory.
         */
        pluginlocation = newfile;
        // The plugin constructor does the job of loading the constructor.
  
    }
    
    public void loadPlugin() throws Exception{
        
        
        /** The loadPlugin Function loads plugins from the files into the memory. 
         *  if this fails for any reason, exceptions are thrown to the parent class.
         * 
         * Common Exceptions Thrown Are
         * MalformedURLException
         * ClassNotFoundException (if the file is not a .class file)
         * IOException (general read/write errors, possibly caused by tampering of the system)
         * InstantiationException (Class is not loadable)
         * IllegalAccessAcception (Class may be in use)
         * NotRunnableException (thrown if class is not of type runnable)
         */
        
        File temp = pluginlocation.getParentFile().getParentFile();
        // The way this is done is using URLs. The plugin is converted to a URL and then converted back
        // This is done so that the system is more extensible - the pluginloader can be modified to
        // Load Plugins from a website, for example
        
        URL url = temp.toURL();          
        URL[] urls = new URL[]{url};
        ClassLoader cl = new URLClassLoader(urls);
        
        // This warrents a bit of extra explanation. The plugin will have to be put in
        // a folder with the same name as the package
        // e.g
        // If Hell.class is in package Hell
        // C:\Hell\Hell.class is acceptable
        // C:\Heaven\Hell.class is not acceptable
        // which is it's packagename, or an Exception will be thrown.
        // The plugin CANNOT be in the root directory of an exception will be thrown too.
        
        Class cls = cl.loadClass(pluginlocation.getParentFile().getName() + "." + pluginlocation.getName().subSequence(0, pluginlocation.getName().length() - 6).toString());
        
        // A new instance of the class is created.
        newclass = cls.newInstance();
        
        if (!(newclass instanceof Runnable)){
            // Throws an exceptio if the plugin is not runnable
            throw new NotRunnableException();
        }
        
        if (newclass instanceof RunnableBuddy){
            // Changes the name if the plugin happens to be of type Runnable Buddy
            RunnableBuddy temp2 = (RunnableBuddy)newclass;
            name = temp2.getName();
        }
        else{
            name = pluginlocation.toString();
        }

        loaded = true;
        
    }
    
    public void runplugin(){     

        /** Makes sure the plugin is Runnable and then
         * Runs the plugin. Right now runplugin is coupled with LoginInfo - it 
         * pushes the current user's login info to the client. THis can be decoupled
         * easily in future versions.
         */
        
        // If the Plugin is a Runnable Buddy
        if (newclass instanceof RunnableBuddy){
            // We push the current user's login info (which is stored as a static variable
            // to the plugin. Future implementations will be able to push more information
            // to the plugin.
             LoginInfo newLoginInfo = new LoginInfo();
            ((RunnableBuddy)newclass).setLoginInfo(newLoginInfo.getUsernameInfo());
        }     
        
        if (newclass instanceof Runnable){
            // If it's not Runnable, we simply run the plugin. The Plugin will not take
            // Advantage of any other special features of the StuddyBuddy Architecture
            plugin = (Runnable)newclass;
            plugin.run();
        }     
         
   }
    
    public String getName(){
     
        /** Returns the name of the Buddy*/
        
        if (newclass instanceof RunnableBuddy){
            // If it is a runnable Buddy, the name will be hard-coded into the Buddy
            RunnableBuddy temp = (RunnableBuddy)newclass;
            return temp.getName();
        }
        else{
            // Otherwise it simply returns the location of the file.
            return name;
        }
        
        
    }
    
    public int getScore(){
        
        /** Returns the buddies current score. Only applies to Runnable Buddies*/
        
        if (newclass instanceof RunnableBuddy){
            // If the newclass is an instance of Runnable Buddy, well then we get the score
            RunnableBuddy temp = (RunnableBuddy)newclass; 
            return temp.getScore();
            
        }
        
        return 0;
    }
   
    public String toString(){
        
        // The toString function of the buddy is overwritten to return the plugin's location
        // In the file system
        
        return pluginlocation.toString();
        
    }
    
    /*NOTE THESE FUNCTIONS ARE NOT WORKING PLEASE IGNORE*/
    /*NOTE THESE FUNCTIONS ARE NOT WORKING PLEASE IGNORE*/
    
    /*
    public void saveGameToFile(){
        
        
        LoginInfo newLoginInfo = new LoginInfo();
        RunnableBuddy temp = null;

        if (newclass instanceof RunnableBuddy){
            // If the newclass is an instance of Runnable Buddy, well then we get the score
            temp = (RunnableBuddy)newclass; 
            
        }

        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        try
        {
          fos = new FileOutputStream(newLoginInfo.getUsernameInfo() + ((RunnableBuddy)newclass).getName().hashCode());
          out = new ObjectOutputStream(fos);
          out.writeObject(temp.getSavedGame());
          out.close();
        }
        catch(IOException e)
        {
          e.printStackTrace();
        }
        
      }
        
    
    
    public void loadSavedGameFromFile(){
    
      FileInputStream fis = null;
      ObjectInputStream in = null;
      LoginInfo newLoginInfo = new LoginInfo();
      RunnableBuddy temp = null;
      Serializable savedgame = null;
            
      if (newclass instanceof RunnableBuddy){
          // If the newclass is an instance of Runnable Buddy, well then we get the score
          temp = (RunnableBuddy)newclass;       
      }
      
      try{
        fis = new FileInputStream(newLoginInfo.getUsernameInfo() + ((RunnableBuddy)newclass).getName().hashCode());
        in = new ObjectInputStream(fis);
        savedgame = (Serializable)in.readObject();
        temp.loadSavedGame(savedgame);

        in.close();
      }
      
      catch(IOException ex)
      {
        System.out.println("No Saved Games Yet");
      }
      catch(ClassNotFoundException ex)
      {
        System.out.println("CN EXCEPTION CAUGHT");
      }
    
    } 
    */
    
    
    
}
